﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Transactions;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using DotNetOpenAuth.AspNet;
using Microsoft.Web.WebPages.OAuth;
using WebMatrix.WebData;
using prjYan.Forum.Filters;
using prjYan.Forum.Models;
using YanForum.Engine.ViewModels;
using YanForum.Engine.Services;
using Postal;
using System.Net.Mail;
using System.Net;

namespace prjYan.Forum.Controllers
{
    [InitializeSimpleMembership]
    public class AccountController : Controller
    {
        //
        // GET: /Account/Login

        [AllowAnonymous]
        public ActionResult Login(string returnUrl)
        {
            ViewBag.ReturnUrl = returnUrl;
            return View();
        }

        //
        // POST: /Account/Login

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult Login(LoginModel model, string returnUrl)
        {
            if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
            {
                return RedirectToLocal(returnUrl);
            }

            // If we got this far, something failed, redisplay form
            ModelState.AddModelError("", "Tên đăng nhập hoặc mật khẩu không đúng.");
            return View(model);
        }

        //
        // POST: /Account/LogOff

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult LogOff()
        {
            WebSecurity.Logout();

            return RedirectToAction("Index", "Home");
        }

        #region Register

        //
        // GET: /Account/Register

        [AllowAnonymous]
        public ActionResult Register()
        {
            return View();
        }

        //
        // POST: /Account/Register

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult Register(RegisterModel model)
        {

            if (ModelState.IsValid)
            {
                //Custom check Exist Email
                #region  Custom check Exist Email

                var getUserEmail = Account.GetUserByEmail(model.Email);
                if (getUserEmail != null && getUserEmail.UserId != 0)
                {
                    ModelState.AddModelError("ExistEmail", string.Format("Email {0} đã tồn tại, vui lòng nhập email khác", model.Email));
                    return View(model);
                }

                #endregion

                // Attempt to register the user
                try
                {
                    //WebSecurity.CreateUserAndAccount(model.UserName, model.Password, new { Email = model.Email, FullName = model.FullName });
                    #region Confirm email

                    string confirmationToken = WebSecurity.CreateUserAndAccount(model.UserName, model.Password, new { Email = model.Email, FullName = model.FullName, CreateDate = DateTime.Now }, true);

                    //Custom Default Roles
                    #region Custom Default Roles

                    if (!Roles.RoleExists("User"))
                        Roles.CreateRole("User");
                    Roles.AddUserToRole(model.UserName, "User");

                    #endregion


                    dynamic email = new Email("RegEmail");
                    email.To = model.Email;
                    email.UserName = model.UserName;
                    email.Domain = YanForum.Engine.Services.BaseService.GetDomain;
                    email.ConfirmationToken = confirmationToken;
                    email.Send();

                    return RedirectToAction("RegisterStepTwo", "Account");

                    #endregion

                    //WebSecurity.Login(model.UserName, model.Password);
                    //return RedirectToAction("Index", "Home");
                }
                catch (MembershipCreateUserException e)
                {
                    ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

        #region Send Email

        //public void EmailSend(string emailTo, string userName,string token)
        //{
        //    MailMessage message = new MailMessage();
        //    message.To.Add(emailTo);
        //    message.From = new MailAddress("ntprj001@gmail.com");
        //    message.Subject = "Email tự động từ Yan";
        //    message.Body =
        //        "Hello " + userName + "," +
        //         "Để hoàn thành việc đăng ký, bạn vui lòng click vào link dưới để kích hoạt tài khoản. <br/>" +
        //         "http://pmh.workmientay.com/Account/RegisterConfirmation/" + token;
        //    message.IsBodyHtml = true;
        //    message.BodyEncoding = System.Text.Encoding.ASCII;
        //    //message.Priority = System.Net.Mail.MailPriority.High;
        //    SmtpClient smtp = new SmtpClient();
        //    smtp.EnableSsl = true;
        //    //smtp.Port = 465;
        //    smtp.Port = 587;
        //    smtp.UseDefaultCredentials = false;
        //    smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
        //    smtp.Host = "smtp.gmail.com";
        //    smtp.Credentials = new NetworkCredential("ntprj001@gmail.com", "0977690727");
        //    try
        //    {
        //        smtp.Send(message);
        //    }
        //    catch (Exception ex)
        //    {
        //        throw ex;
        //    }
        //}

        #endregion

        [AllowAnonymous]
        public ActionResult RegisterStepTwo()
        {
            return View();
        }

        [AllowAnonymous]
        public ActionResult RegisterConfirmation(string Id)
        {
            if (WebSecurity.ConfirmAccount(Id))
            {
                return RedirectToAction("ConfirmationSuccess");
            }
            return RedirectToAction("ConfirmationFailure");
        }

        [AllowAnonymous]
        public ActionResult ConfirmationSuccess()
        {
            return View();
        }

        [AllowAnonymous]
        public ActionResult ConfirmationFailure()
        {
            return View();
        }

        #endregion

        //
        // POST: /Account/Disassociate

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Disassociate(string provider, string providerUserId)
        {
            string ownerAccount = OAuthWebSecurity.GetUserName(provider, providerUserId);
            ManageMessageId? message = null;

            // Only disassociate the account if the currently logged in user is the owner
            if (ownerAccount == User.Identity.Name)
            {
                // Use a transaction to prevent the user from deleting their last login credential
                using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.Serializable }))
                {
                    bool hasLocalAccount = OAuthWebSecurity.HasLocalAccount(WebSecurity.GetUserId(User.Identity.Name));
                    if (hasLocalAccount || OAuthWebSecurity.GetAccountsFromUserName(User.Identity.Name).Count > 1)
                    {
                        OAuthWebSecurity.DeleteAccount(provider, providerUserId);
                        scope.Complete();
                        message = ManageMessageId.RemoveLoginSuccess;
                    }
                }
            }

            return RedirectToAction("Manage", new { Message = message });
        }

        //
        // GET: /Account/Manage
        //Go to /Admin/AccountAdmin/Manage

        //
        // POST: /Account/ExternalLogin

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult ExternalLogin(string provider, string returnUrl)
        {
            return new ExternalLoginResult(provider, Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));
        }

        //
        // GET: /Account/ExternalLoginCallback

        [AllowAnonymous]
        public ActionResult ExternalLoginCallback(string returnUrl)
        {
            AuthenticationResult result = OAuthWebSecurity.VerifyAuthentication(Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));
            if (!result.IsSuccessful)
            {
                return RedirectToAction("ExternalLoginFailure");
            }

            if (OAuthWebSecurity.Login(result.Provider, result.ProviderUserId, createPersistentCookie: false))
            {
                return RedirectToLocal(returnUrl);
            }

            if (User.Identity.IsAuthenticated)
            {
                // If the current user is logged in add the new account
                OAuthWebSecurity.CreateOrUpdateAccount(result.Provider, result.ProviderUserId, User.Identity.Name);
                return RedirectToLocal(returnUrl);
            }
            else
            {
                // User is new, ask for their desired membership name
                string loginData = OAuthWebSecurity.SerializeProviderUserId(result.Provider, result.ProviderUserId);
                ViewBag.ProviderDisplayName = OAuthWebSecurity.GetOAuthClientData(result.Provider).DisplayName;
                ViewBag.ReturnUrl = returnUrl;
                return View("ExternalLoginConfirmation", new RegisterExternalLoginModel
                {
                    UserName = result.UserName,
                    Email = result.UserName,
                    ExternalLoginData = loginData
                });
            }
        }

        //
        // POST: /Account/ExternalLoginConfirmation

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult ExternalLoginConfirmation(RegisterExternalLoginModel model, string returnUrl)
        {
            string provider = null;
            string providerUserId = null;

            if (User.Identity.IsAuthenticated || !OAuthWebSecurity.TryDeserializeProviderUserId(model.ExternalLoginData, out provider, out providerUserId))
            {
                return RedirectToAction("Manage");
            }

            if (ModelState.IsValid)
            {
                // Insert a new user into the database
                using (UsersContext db = new UsersContext())
                {
                    //UserProfile user = db.UserProfiles.FirstOrDefault(u => u.UserName.ToLower() == model.UserName.ToLower());
                    //Custom by Tuan:
                    UserProfile user = db.UserProfiles.FirstOrDefault(u => u.UserName.ToLower() == model.UserName.ToLower() && u.Email.ToLower() == model.Email.ToLower());
                    // Check if user already exists
                    if (user == null)
                    {
                        // Insert name into the profile table
                        db.UserProfiles.Add(new UserProfile
                        {
                            UserName = model.UserName,
                            Email = model.Email,
                            FullName = model.FullName,
                            CreateDate = DateTime.Now
                        });
                        db.SaveChanges();

                        //Custom Default Roles
                        #region Custom Default Roles

                        if (!Roles.RoleExists("User"))
                            Roles.CreateRole("User");
                        Roles.AddUserToRole(model.UserName, "User");

                        #endregion

                        OAuthWebSecurity.CreateOrUpdateAccount(provider, providerUserId, model.UserName);
                        OAuthWebSecurity.Login(provider, providerUserId, createPersistentCookie: false);

                        return RedirectToLocal(returnUrl);
                    }
                    else
                    {
                        ModelState.AddModelError("UserName", "Tên đăng nhập hoặc email đã tồn tại đã tồn tại, vui lòng chọn tên đăng nhập khác.");
                    }
                }
            }

            ViewBag.ProviderDisplayName = OAuthWebSecurity.GetOAuthClientData(provider).DisplayName;
            ViewBag.ReturnUrl = returnUrl;
            return View(model);
        }

        //
        // GET: /Account/ExternalLoginFailure

        [AllowAnonymous]
        public ActionResult ExternalLoginFailure()
        {
            return View();
        }

        [AllowAnonymous]
        [ChildActionOnly]
        public ActionResult ExternalLoginsList(string returnUrl)
        {
            ViewBag.ReturnUrl = returnUrl;
            return PartialView("_ExternalLoginsListPartial", OAuthWebSecurity.RegisteredClientData);
        }

        #region Forget Password

        // GET: Account/LostPassword
        [AllowAnonymous]
        public ActionResult LostPassword()
        {
            if (Request.IsAuthenticated)
                return Redirect("/");

            return View();
        }

        // POST: Account/LostPassword
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult LostPassword(LostPasswordModel model)
        {
            if (ModelState.IsValid)
            {
                var _user = YanForum.Engine.Services.Account.GetUserByEmail(model.Email);

                if (_user != null && _user.UserId != 0)
                {
                    // Generae password token that will be used in the email link to authenticate user
                    var token = WebSecurity.GeneratePasswordResetToken(_user.UserName);
                    
                    //

                    dynamic email = new Email("ForgotPassword");
                    email.To = model.Email;
                    email.UserName = _user.UserName;
                    email.Domain = YanForum.Engine.Services.BaseService.GetDomain;

                    // Generate the html link sent via email
                    string resetLink = Url.Action("ResetPassword", "Account", new { rt = token }, "http");

                    email.Link = resetLink;

                    // Attempt to send the email
                    try
                    {
                        email.Send();

                        ViewBag.Message = "Đã gửi link đặt lại mật khẩu đến email " + model.Email + " , Bạn vui lòng vào check mail!" ;
                    }
                    catch (Exception e)
                    {
                        ModelState.AddModelError("", "Gửi email không thành công: " + e.Message);
                    }
                }
                else // Email not found
                {
                    ModelState.AddModelError("", "Không tìm thấy email!");
                }
            }
            return View(model);
        }


        // GET: /Account/ResetPassword
        [AllowAnonymous]
        public ActionResult ResetPassword(string rt)
        {
            if (Request.IsAuthenticated)
                return Redirect("/");

            ResetPasswordModel model = new ResetPasswordModel();
            model.ReturnToken = rt;
            return View(model);
        }

        // POST: /Account/ResetPassword
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult ResetPassword(ResetPasswordModel model)
        {
            if (ModelState.IsValid)
            {
                bool resetResponse = WebSecurity.ResetPassword(model.ReturnToken, model.Password);
                if (resetResponse)
                {
                    ViewBag.Message = "Đã đặt lại mật khẩu thành công!";
                }
                else
                {
                    ViewBag.Message = "Đặt lại mật khẩu không thành công!";
                }
            }
            return View(model);
        }


        #endregion

        #region Helpers
        private ActionResult RedirectToLocal(string returnUrl)
        {
            if (Url.IsLocalUrl(returnUrl))
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }


        internal class ExternalLoginResult : ActionResult
        {
            public ExternalLoginResult(string provider, string returnUrl)
            {
                Provider = provider;
                ReturnUrl = returnUrl;
            }

            public string Provider { get; private set; }
            public string ReturnUrl { get; private set; }

            public override void ExecuteResult(ControllerContext context)
            {
                OAuthWebSecurity.RequestAuthentication(Provider, ReturnUrl);
            }
        }

        private static string ErrorCodeToString(MembershipCreateStatus createStatus)
        {
            // See http://go.microsoft.com/fwlink/?LinkID=177550 for
            // a full list of status codes.
            switch (createStatus)
            {
                case MembershipCreateStatus.DuplicateUserName:
                    return "Tên đăng nhập đã tồn tại, vui lòng nhập tên khác.";

                case MembershipCreateStatus.DuplicateEmail:
                    return "A user name for that e-mail address already exists. Please enter a different e-mail address.";

                case MembershipCreateStatus.InvalidPassword:
                    return "The password provided is invalid. Please enter a valid password value.";

                case MembershipCreateStatus.InvalidEmail:
                    return "The e-mail address provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidAnswer:
                    return "The password retrieval answer provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidQuestion:
                    return "The password retrieval question provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidUserName:
                    return "The user name provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.ProviderError:
                    return "The authentication provider returned an error. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

                case MembershipCreateStatus.UserRejected:
                    return "The user creation request has been canceled. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

                default:
                    return "An unknown error occurred. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
            }
        }
        #endregion

        #region Ajax

        [HttpPost]
        public ActionResult AjaxSubmitInfoGuest(string fullName, string email)
        {
            if (!string.IsNullOrEmpty(fullName) && !string.IsNullOrEmpty(email))
            {
                if (!YanForum.Engine.Services.StringExtension.ValidateEmail(email))
                    return Json(new { status = false, message = "Email không đúng!" });

                #region  Custom check Exist Email

                var getUserEmail = Account.GetUserByEmail(email);
                if (getUserEmail != null && getUserEmail.UserId != 0)
                {
                    return Json(new { status = false, message = "Email: " + email + " đã tồn tại, bạn vui lòng đăng nhập hoặc chọn quên mật khẩu!" });
                }

                #endregion

                try
                {
                    string randomPass = YanForum.Engine.Services.StringExtension.RandomString(6);
                    WebSecurity.CreateUserAndAccount(email, randomPass, new { Email = email, FullName = fullName, CreateDate = DateTime.Now });

                    #region Custom Default Roles

                    if (!Roles.RoleExists("User"))
                        Roles.CreateRole("User");
                    Roles.AddUserToRole(email, "User");

                    #endregion

                    WebSecurity.Login(email, randomPass);

                    return Json(new { status = true });
                }
                catch (Exception ex)
                {
                    return Json(new { status = false, message = "Tạo thông tin không thành công!" });
                }
            }
            return Json(new { status = false, message = "Vui lòng nhập đầy đủ thông tin!" });
        }

        [HttpPost]
        public ActionResult AjaxLogin(string userName, string passWord)
        {
            if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(passWord))
            {
                if (WebSecurity.Login(userName, passWord, persistCookie: true))
                {
                    return Json(new { status = true });
                }
                else
                {
                    return Json(new { status = false, message = "Tên đăng nhập hoặc mật khẩu!" });
                }
            }
            return Json(new { status = false, message = "Vui lòng nhập tên đăng nhập và mật khẩu!" });
        }

        #endregion
    }
}
